package org.kth.dks.util;

/**
 * Future implements a facility to wait for the result of an
 * asynchronous computation. It is meant to be an implementation of the
 * java.util.concurrent.Future interface, although to be compilable with JSE 1.4,
 * generics are not used. If you have 5.0, probably use java.util.concurrent.FutureTask instead.
 * The future class decouples the underlying computations from the return mechanism.
 * That is, the cancel method will never actually cancel any computation that computes
 * the value of the future.
 * The class supports multiple waiters.
 */
public class Future {
    boolean completed;
    boolean cancelled;
    Exception exception = null;
    Object value;

    public Future() { }
    public Future(Object value) { this.value = value; completed = true; }

    /* Retrieves the value of a computation. Waits until the
     * value is available.
     */
    public synchronized Object get()
	throws InterruptedException, CancellationException, Exception {
	while (!completed && !cancelled) {
	    this.wait();
	}
	if (completed) return value;
        else {
          if (exception!=null)
            throw exception;
          else
            throw new CancellationException();
        }
    }

    long now() { return new java.util.Date().getTime(); }

    /* Retrieves the value of a computation. Waits at most timeout milliseconds
     * for the value of the computation to become available.
     */
    public synchronized Object get(long timeout)
	throws TimeoutException, InterruptedException, CancellationException {
	long waitUntil = now() + timeout;
	long waitTime = timeout;

	while(!completed && !cancelled) {
	    this.wait(waitTime);
	    if (!completed && !cancelled) {
		waitTime = waitUntil-now();
		if (waitTime<=0) throw new TimeoutException();
	    }
	}
	if (completed) return value;
	else throw new CancellationException();
    }

    /* Returns true if the computation has finished and false otherwise.
     */
    public synchronized boolean isDone() {
	return completed;
    }

    /* Returns true if the computation has finished and false otherwise.
     */
    public synchronized boolean isCancelled() {
	return cancelled;
    }

    /* Signals that a value has been computed so that waiting readers can
     * continue.
     */
    public synchronized void store(Object value) {
	if (!completed && !cancelled) {
	    this.value = value;
	    completed = true;
	    this.notifyAll();
	}
    }

    /* Prevents the return of any (later) computed results.
     */
    public synchronized void cancel(boolean mayInterruptIfRunning) {
	if (!completed) cancelled = true;
	this.notifyAll();
    }

    public synchronized void cancel(Exception ex) {
      exception = ex;
      if (!completed) cancelled = true;
      this.notifyAll();
    }
}
